﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GobangApplication
{
    public partial class FrmGobang : Form
    {
        private bool finish;  //判断是否结束
        private int[,] chess; //存储棋盘信息
        private int counter;  //通过奇偶记录顺序
        private int size;     //棋盘的大小
        private int X, Y;     //相对棋盘的横纵坐标
        private int q1, q2;   //行和列
        private Graphics g;   //绘制线和棋子
        private int[] Xstack; //栈存储横坐标
        private int[] Ystack; //栈存储纵坐标
        private int stackTop; //栈顶指针

        public FrmGobang()
        {
            /*构造函数初始化*/
            InitializeComponent();
            this.finish = false;                          //初始设置为未结束
            this.size = 19;                               //初始设置棋盘大小最大
            this.chess = new int[this.size, this.size];   //初始设置棋盘二维数组
            this.Xstack = new int[this.size * this.size]; //初始设置横坐标栈
            this.Ystack = new int[this.size * this.size]; //初始设置纵坐标栈
            this.counter = 0;                             //初始设置顺序计数器为0
        }

        private void DrawLines()
        {
            /*画出棋盘格子*/
            g = CreateGraphics();
            for (int i = 0; i < size; i++)
            {
                //大小不定，随size变化
                g.DrawLine(new Pen(Color.Black), new Point(50, 50 + i * 20),
                    new Point(50 + (size - 1) * 20, 50 + i * 20));
                g.DrawLine(new Pen(Color.Black), new Point(50 + i * 20, 50),
                    new Point(50 + i * 20, 50 + (size - 1) * 20));
            }
        }

        private void ClearChessboard()
        {
            /*将棋盘状态数组全部重置为0，及未下棋状态*/
            for (int i = 0; i < this.size; i++)
            {
                for (int j = 0; j < this.size; j++)
                {
                    this.chess[i, j] = 0;
                }
            }

        }

        private void DrawCircle(int c, int x, int y)
        {
            /*画出棋子函数*/
            g = this.CreateGraphics();
            if (c % 2 == 1)//圆的外接矩形的左上角为(x-9,y-9)
                g.FillEllipse(Brushes.White, x - 9, y - 9, 18, 18);
            else//长轴、短轴均为18的椭圆，即一个直径18的圆
                g.FillEllipse(Brushes.Black, x - 9, y - 9, 18, 18);
        }

        private void ResetBoard()
        {
            /*清空棋盘上所有的棋子*/
            g.Clear(this.BackColor); //背景色填充
            ClearChessboard();       //重置棋盘数组
            counter = 0;             //顺序重新开始
            finish = false;          //游戏重启，未结束
        }
        private bool IsWin()
        {
            /*判断胜负开始*/

            //横向判断
            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size - 4; j++)
                {
                    if (chess[i, j] == 1 &&
                        chess[i, j + 1] == 1 &&
                        chess[i, j + 2] == 1 &&
                        chess[i, j + 3] == 1 &&
                        chess[i, j + 4] == 1)
                    {
                        MessageBox.Show("White Win!");
                        return true;
                    }
                    if (chess[i, j] == 2 &&
                        chess[i, j + 1] == 2 &&
                        chess[i, j + 2] == 2 &&
                        chess[i, j + 3] == 2 &&
                        chess[i, j + 4] == 2)
                    {
                        MessageBox.Show("Black Win!");
                        return true;
                    }
                }
            }
            //纵向判断
            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size - 4; j++)
                {
                    if (chess[j, i] == 1 &&
                        chess[j + 1, i] == 1 &&
                        chess[j + 2, i] == 1 &&
                        chess[j + 3, i] == 1 &&
                        chess[j + 4, i] == 1)
                    {
                        MessageBox.Show("White Win!");
                        return true;
                    }
                    if (chess[j, i] == 2 &&
                        chess[j + 1, i] == 2 &&
                        chess[j + 2, i] == 2 &&
                        chess[j + 3, i] == 2 &&
                        chess[j + 4, i] == 2)
                    {
                        MessageBox.Show("Black Win!");
                        return true;
                    }
                }
            }
            //主对角线
            for (int i = 0; i < size - 4; i++)
            {
                for (int j = 0; j < size - 4; j++)
                {
                    if (chess[i, j] == 1 &&
                        chess[i + 1, j + 1] == 1 &&
                        chess[i + 2, j + 2] == 1 &&
                        chess[i + 3, j + 3] == 1 &&
                        chess[i + 4, j + 4] == 1)
                    {
                        MessageBox.Show("White Win!");
                        return true;
                    }
                    if (chess[i, j] == 2 &&
                        chess[i + 1, j + 1] == 2 &&
                        chess[i + 2, j + 2] == 2 &&
                        chess[i + 3, j + 3] == 2 &&
                        chess[i + 4, j + 4] == 2)
                    {
                        MessageBox.Show("Black Win!");
                        return true;
                    }
                }
            }
            //副对角线
            for (int i = 0; i < size - 4; i++)
            {

                for (int j = 4; j < size; j++)
                {
                    if (chess[i, j] == 1 &&
                        chess[i + 1, j - 1] == 1 &&
                        chess[i + 2, j - 2] == 1 &&
                        chess[i + 3, j - 3] == 1 &&
                        chess[i + 4, j - 4] == 1)
                    {
                        MessageBox.Show("White Win!");
                        return true;
                    }
                    if (chess[i, j] == 2 &&
                        chess[i + 1, j - 1] == 2 &&
                        chess[i + 2, j - 2] == 2 &&
                        chess[i + 3, j - 3] == 2 &&
                        chess[i + 4, j - 4] == 2)
                    {
                        MessageBox.Show("Black Win!");
                        return true;
                    }

                }
            }
            /*判断胜负结束*/
            return false;
        }
        void SetChess(object sender, MouseEventArgs e)
        {
            //得到对应的行数q1和列数q2
            X = Y = 0;
            q1 = q2 = 0;
            for (int i = 0; i < size; i++)
            {
                if (e.X >= i * 20 + 50 - 8 && e.X <= i * 20 + 50 + 8)
                {
                    X = i * 20 + 50;
                    q1 = i;
                }
                if (e.Y >= i * 20 + 50 - 8 && e.Y <= i * 20 + 50 + 8)
                {
                    Y = i * 20 + 50;
                    q2 = i;
                }
            }

            //在一定范围内点击都能画出棋子
            if (X >= 0 * size + 50 - 9 && X <= 50 + (size - 1) * 20 &&
                Y >= 0 * size + 50 - 9 && Y <= 50 + (size - 1) * 20 &&
                chess[q2, q1] == 0 && counter % 2 == 0)
            {
                chess[q2, q1] = 2;
                DrawCircle(counter, X, Y);
                stackTop = counter++;
                Xstack[stackTop] = q1;
                //不能重复点两次
                Ystack[stackTop] = q2;

            }
            if (X >= 0 * size + 50 - 9 && X <= 50 + (size - 1) * 20 &&
                Y >= 0 * size + 50 - 9 && Y <= 50 + (size - 1) * 20 &&
                 chess[q2, q1] == 0 && counter % 2 != 0)
            {
                chess[q2, q1] = 1;
                DrawCircle(counter, X, Y);
                stackTop = counter++;
                Xstack[stackTop] = q1;
                Ystack[stackTop] = q2;
            }
        }

        private void LoadBorad()
        {
            /*加载菜单和相应的按钮选项*/
            panel1.Visible = false;
            this.Height = 120 + size * 20;
            this.Width = 100 + size * 20;

            Point p1 = new Point(this.Width / 2 - 52, this.Height - 75);
            Point p2 = new Point(10, this.Height - 75);
            Point p3 = new Point(this.Width - 90, this.Height - 75);
            BtnReGame.Location = p1;
            BtnBackMenu.Location = p3;
            BtnRepent.Location = p2;
            BtnReGame.Visible = true;
            BtnBackMenu.Visible = true;
            BtnRepent.Visible = true;
            DrawLines();
        }

        private void BtnNine_Click(object sender, EventArgs e)
        {
            size = 9;
            LoadBorad();
        }

        private void BtnThirteen_Click(object sender, EventArgs e)
        {
            size = 13;
            LoadBorad();
        }

        private void BtnFifteen_Click(object sender, EventArgs e)
        {
            size = 15;
            LoadBorad();
        }

        private void BtnNineteen_Click(object sender, EventArgs e)
        {
            size = 19;
            LoadBorad();
        }

        private void BtnExit_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("您确定要退出游戏吗？",
                "确认", MessageBoxButtons.OKCancel);
            if (result == DialogResult.OK)
            {
                Application.Exit();
            }

        }

        private void BtnRepent_Click(object sender, EventArgs e)
        {
            /*悔棋操作*/
            DialogResult result = MessageBox.Show("您确定要悔一步棋吗？",
                "确认", MessageBoxButtons.OKCancel);
            if (result == DialogResult.OK && finish == false)
            {
                if (stackTop == 0)
                {
                    ResetBoard();
                    DrawLines();
                }
                else if (stackTop != -1)
                {
                    //将最后的棋子对应的数据结构标记为未下棋
                    chess[Ystack[stackTop], Xstack[stackTop]] = 0;
                    stackTop--;
                    counter--;
                    g.Clear(this.BackColor);
                    DrawLines();
                    int X, Y;
                    for (int i = 0; i < size; i++)
                    {
                        for (int j = 0; j < size; j++)
                        {
                            if (chess[i, j] != 0)
                            {
                                Y = i * 20 + 50;
                                X = j * 20 + 50;
                                DrawCircle(chess[i, j], X, Y);
                            }
                        }
                    }

                }
            }

        }

        private void BtnReGame_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("您确定要重新开始游戏吗？",
               "确认", MessageBoxButtons.OKCancel);
            if (result == DialogResult.OK)
            {
                ResetBoard();
                DrawLines();
            }
        }

        private void BtnBackMenu_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("您确定要回到菜单吗？",
               "确认", MessageBoxButtons.OKCancel);
            if (result == DialogResult.OK)
            {
                panel1.Visible = true;
                BtnReGame.Visible = false;
                BtnBackMenu.Visible = false;
                BtnRepent.Visible = false;
                ResetBoard();
                this.Height = 120 + 9 * 20;
                this.Width = 100 + 10 * 20;
            }
        }

        private void FrmGobang_MouseClick(object sender, MouseEventArgs e)
        {
            if (finish == false)
            {
                SetChess(sender, e);
                finish = IsWin();
                if (finish)
                {
                    Output2File();
                }
            }

        }

        private void Output2File()
        {
            string saved = @"./saved";
            string time = DateTime.Now.ToString("yyyyMMddHHmmss");
            if (!System.IO.Directory.Exists(saved))
            {
                System.IO.Directory.CreateDirectory(saved);
            }
            int[,] writeArray = Aarry2Sparse();
            for (int i = 0; i < writeArray[0, 2] + 1; i++)
            {

                System.IO.File.AppendAllText(@"./saved/" + time + ".txt",
                    writeArray[i, 0] + " " + writeArray[i, 1] + " " + writeArray[i, 2] + "\n",
                    Encoding.UTF8);

            }

        }

        private int[,] Aarry2Sparse()
        {
            int sum = 0;

            foreach (int item in chess)
            {
                if (item != 0)
                {
                    sum++;
                }
            }
            int k = 1;
            int[,] sparseArray = new int[sum + 1, 3];
            sparseArray[0, 0] = size;
            sparseArray[0, 1] = size;
            sparseArray[0, 2] = sum;

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    if (chess[i, j] != 0)
                    {
                        sparseArray[k, 0] = i;
                        sparseArray[k, 1] = j;
                        sparseArray[k, 2] = chess[i, j];
                        k++;
                    }
                }
            }
            return sparseArray;
        }
    }
}